package com.kaxiu.config.redis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.kaxiu.config.shiro.jwt.JwtConfig;
import com.kaxiu.config.shiro.jwt.JwtToken;
import com.kaxiu.persistent.entity.BasicUser;
import com.kaxiu.persistent.mapper.BasicUserMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

import static com.kaxiu.config.CommonConstant.RedisKey.*;

/**
 * @author: LiYang
 * @create: 2019-08-12 21:17
 * @Description:
 **/
@Service("redisService")
public class RedisServiceImpl implements RedisService {

    @Autowired
    private BasicUserMapper userMapper;

    @Autowired
    private JwtConfig jwtConfig;

    @Resource
    private RedisTemplate<String, ?> redisTemplate;

    @Override
    public boolean setLocation(JSONObject location) {
        BasicUser user = getWxUser();
        String key = String.format(SERVER_LOCATION, user.getId());
        return this.set(key, location.toJSONString(), Long.valueOf(60 * 60 * 24 * 7));
    }

    @Override
    public boolean setLocation(Long userId, JSONObject location) {
        String key = String.format(SERVER_LOCATION, userId);
        return this.set(key, location.toJSONString(), Long.valueOf(60 * 60 * 24 * 7));
    }

    @Override
    public JSONObject getLocation() {
        BasicUser user = getWxUser();
        String key = String.format(SERVER_LOCATION, user.getId());
        return JSONObject.parseObject(get(key));
    }

    @Override
    public boolean setMobileCode(String mobile, String code) {
        BasicUser user = getWxUser();
        String key = String.format(MOBILE_CODE, user.getId(), mobile);
        return this.set(key, code, Long.valueOf(5 * 60));
    }

    @Override
    public String getMobileCode(String mobile) {
        BasicUser user = getWxUser();
        String key = String.format(MOBILE_CODE, user.getId(), mobile);
        return get(key);
    }

    @Override
    public boolean set(final String key, final String value) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            connection.set(serializer.serialize(key), serializer.serialize(value));
            return true;
        });
    }

    @Override
    public boolean set(String key, String value, Long expire) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            connection.setEx(serializer.serialize(key), expire, serializer.serialize(value));
            return true;
        });
    }

    /**
     * redis中存储七天，要注意更新，每次user有变动都需要手动更新
     * user 可以从登陆信息里获取openid、也可以从自己的bean里
     * @param user
     * @return
     */
    @Override
    public boolean setWxUser(BasicUser user) {
        String openId;
        if(user != null && StringUtils.isNotEmpty(user.getOpenId())){
            openId = user.getOpenId();
        }else{
            JwtToken token = (JwtToken) SecurityUtils.getSubject().getPrincipal();
            openId = jwtConfig.getWxOpenIdByToken(token.getToken());
        }
        String key = String.format(USERINFO, openId);
        return this.set(key, JSON.toJSONString(user), Long.valueOf(7 * 24 * 3600));
    }

    @Override
    public BasicUser getWxUser() {
        JwtToken token = (JwtToken) SecurityUtils.getSubject().getPrincipal();
        if (token == null)
            throw new AuthenticationException("user account not exits , please check your token");
        String openId = jwtConfig.getWxOpenIdByToken(token.getToken());
        if(StringUtils.isEmpty(openId))
            throw new AuthenticationException();
        return getByOpenId(openId);
    }

    private BasicUser getByOpenId(String openId){
        String key = String.format(USERINFO, openId);
        String userVal = this.get(key);
        if(StringUtils.isEmpty(userVal)){
            //用户为空，从数据库中取，并更新
            BasicUser user = userMapper.selectOne(Wrappers.<BasicUser>lambdaQuery().eq(BasicUser::getOpenId, openId));
            this.setWxUser(user);
            return user;
        }else{
            BasicUser user = JSON.parseObject(userVal, BasicUser.class);
            return user;
        }
    }

    @Override
    public String get(final String key) {
        return redisTemplate.execute((RedisCallback<String>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            byte[] value = connection.get(serializer.serialize(key));
            return serializer.deserialize(value);
        });
    }

    @Override
    public boolean expire(final String key, long expire) {
        return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    public boolean remove(final String key) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            connection.del(key.getBytes());
            return true;
        });
    }
}
